package com.wondertek.service.service.business.impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wondertek.common.base.Result;
import com.wondertek.common.exception.AppException;
import com.wondertek.common.util.base.DateUtil;
import com.wondertek.common.util.base.PoiUtil;
import com.wondertek.common.util.base.PushUtil;
import com.wondertek.common.util.base.StringUtil;
import com.wondertek.common.util.security.LoginUser;
import com.wondertek.common.util.security.SecurityUtil;
import com.wondertek.service.dto.app.req.AppDerReq;
import com.wondertek.service.dto.app.req.AppDerUpdReq;
import com.wondertek.service.dto.app.res.DeviceErrorRecordKvRes;
import com.wondertek.service.dto.app.res.DeviceErrorRecordListRes;
import com.wondertek.service.dto.business.req.DerConfigAddReq;
import com.wondertek.service.dto.business.req.DevicePageReq;
import com.wondertek.service.dto.business.req.WebDerReq;
import com.wondertek.service.dto.business.res.DerConfigFindRes;
import com.wondertek.service.dto.business.res.DeviceErrorRecordExportRes;
import com.wondertek.service.dto.business.res.TimeZoneDictRes;
import com.wondertek.service.entity.business.*;
import com.wondertek.service.mapper.business.DeviceErrorRecordConfigMapper;
import com.wondertek.service.mapper.business.DeviceErrorRecordMapper;
import com.wondertek.service.mapper.business.RoomMapper;
import com.wondertek.service.sdk.iotdh.dto.req.ComId;
import com.wondertek.service.sdk.iotdh.dto.req.GetAreaInfosReq;
import com.wondertek.service.sdk.iotdh.dto.req.arcConfig.AddArcConfigReq;
import com.wondertek.service.sdk.iotdh.dto.req.arcConfig.AlternativeAddresses;
import com.wondertek.service.sdk.iotdh.dto.req.arcConfig.SIA_DC09;
import com.wondertek.service.sdk.iotdh.dto.res.ArmModesRes;
import com.wondertek.service.sdk.iotdh.dto.res.GetAreaArmModeRes;
import com.wondertek.service.sdk.iotdh.dto.res.PushDhMessage;
import com.wondertek.service.sdk.iotdh.dto.res.arcConfig.GetArcConfigRes;
import com.wondertek.service.sdk.iotdh.service.DhDeviceService;
import com.wondertek.service.service.business.*;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.collections4.CollectionUtils;
import org.mybatis.spring.MyBatisSystemException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.time.ZoneId;
import java.util.*;


/**
 * @author wangyu
 */
@Service
public class DeviceErrorRecordServiceImpl extends ServiceImpl<DeviceErrorRecordMapper, DeviceErrorRecordPo> implements DeviceErrorRecordService {


    @Autowired
    private DeviceErrorRecordMapper deviceErrorRecordMapper;

    @Autowired
    private DhDeviceService dhDeviceService;

    @Autowired
    private DeviceErrorRecordReadService deviceErrorRecordReadService;

    @Autowired
    private DeviceErrorRecordMessageService deviceErrorRecordMessageService;

    @Autowired
    private PushUtil pushUtil;

    @Autowired
    private DeviceService deviceService;

    @Resource
    private IAlarmNoticeSettingService alarmNoticeSettingService;

    @Autowired
    private DeviceErrorRecordConfigMapper deviceErrorRecordConfigMapper;

    @Resource
    private RoomMapper roomMapper;

    /**
     * app查询报警
     *
     * @param appDerReq
     * @return
     */
    public Page<DeviceErrorRecordKvRes> findRecordList(AppDerReq appDerReq) {

        LoginUser loginUser = SecurityUtil.getLoginUser();

        String consumerId = loginUser != null ? loginUser.getUserId() : null;

        if (StringUtil.isEmpty(consumerId))
            throw new AppException("user.id.not.null");

        appDerReq.setConsumerId(consumerId);

        //  appDerReq.setConsumerId("b2437eb445d68bef3e8d534d8e9e4bc8");

        IPage<DeviceErrorRecordListRes> page = deviceErrorRecordMapper.findRecordList(appDerReq, new Page(appDerReq.getPageNo(), appDerReq.getPageSize()));

        Page<DeviceErrorRecordKvRes> resPage = new Page<>();

        List<DeviceErrorRecordListRes> recordList = page.getRecords();

        List<DeviceErrorRecordKvRes> list = new ArrayList<>();

        List<DeviceErrorRecordListRes> deviceErrorRecordListRes = new ArrayList<>();

        for (int i = 0; i < recordList.size(); i++) {

            DeviceErrorRecordListRes record = recordList.get(i);

            String s = DateUtil.formatDate(record.getErrorTime());
            String time = DateUtil.formatTimeNoSeconds(record.getErrorTime());
            record.setTime(time);
            deviceErrorRecordListRes.add(record);

            if (i == recordList.size() - 1) {
                DeviceErrorRecordKvRes deviceErrorRecordKvRes = new DeviceErrorRecordKvRes();
                deviceErrorRecordKvRes.setDate(s);
                deviceErrorRecordKvRes.setRecordList(deviceErrorRecordListRes);
                list.add(deviceErrorRecordKvRes);
                BeanUtil.copyProperties(page, resPage);
                resPage.setRecords(list);
                return resPage;
            }

            DeviceErrorRecordListRes record2 = recordList.get(i + 1);
            String s2 = DateUtil.formatDate(record2.getErrorTime());

            if (!s.equals(s2)) {
                DeviceErrorRecordKvRes deviceErrorRecordKvRes = new DeviceErrorRecordKvRes();
                deviceErrorRecordKvRes.setDate(s);
                deviceErrorRecordKvRes.setRecordList(deviceErrorRecordListRes);
                list.add(deviceErrorRecordKvRes);
                deviceErrorRecordListRes = new ArrayList<>();
            }

        }


        return resPage;
    }

    /**
     * 根据id查询报警详情
     *
     * @param id
     * @return
     */
    public DeviceErrorRecordPo findRecordDetailsById(String id) {
        return deviceErrorRecordMapper.findRecordDetailsById(id);
    }

    /**
     * 根据id修改报警处理结果
     *
     * @param req
     */
    public void updateById(AppDerUpdReq req) {
        DeviceErrorRecordPo deviceErrorRecordPo = new DeviceErrorRecordPo();
        deviceErrorRecordPo.setId(req.getId());
        deviceErrorRecordPo.setStatus(req.getStatus());
        super.updateById(deviceErrorRecordPo);
    }

    /**
     * 根据id修改已读状态
     *
     * @param id
     */
    public void updateAppReadById(String id) {
        LoginUser loginUser = SecurityUtil.getLoginUser();
        String userId = loginUser != null ? loginUser.getUserId() : null;

        if (StringUtil.isEmpty(userId))
            throw new AppException("user.id.not.null");

        deviceErrorRecordReadService.updRead(userId, id);
    }

    @Override
    public void updateWebReadById(String id) {
        DeviceErrorRecordPo deviceErrorRecordPo = new DeviceErrorRecordPo();
        deviceErrorRecordPo.setId(id);
        deviceErrorRecordPo.setIsRead(1);
        super.updateById(deviceErrorRecordPo);
    }

    /**
     * 报警信息回调
     *
     * @param pushDhMessage
     */
    @Transactional(rollbackFor = Exception.class)
    public void rollBackErrorRecord(PushDhMessage pushDhMessage) {
        System.out.println("报警回调进入");

        if (pushDhMessage == null)
            throw new AppException("入参为空");

        if (pushDhMessage.getType() == null /*|| (pushDhMessage.getType() != 1 && pushDhMessage.getType() != 2)*/)
            throw new AppException("入参type错误");

        if (StringUtil.isEmpty(pushDhMessage.getDeviceSn()))
            throw new AppException("入参snCode为空");

        if (StringUtil.isEmpty(pushDhMessage.getMsgType()))
            throw new AppException("入参msgType为空");

        if (pushDhMessage.getAlarmTime() == null)
            throw new AppException("报警时间 alarmTime为空");

        System.out.println(pushDhMessage);


        DeviceErrorRecordPo find = null;
        try {
            //  find = deviceErrorRecordMapper.rollBackFind(pushDhMessage.getDeviceSn(), StringUtil.isNotBlank(deviceErrorRecordPo.getRoomId()) ? Integer.valueOf(deviceErrorRecordPo.getRoomId()) : null);
            find = deviceErrorRecordMapper.findDeviceBySnCode(pushDhMessage.getDeviceSn());
            if (find == null)
                find = deviceErrorRecordMapper.findAccessoryBySnCode(pushDhMessage.getDeviceSn());
        } catch (MyBatisSystemException e) {
            throw new AppException("snCode:" + pushDhMessage.getDeviceSn() + "; 系统中查出两条数据");
        }

        if (find == null)
            throw new AppException("snCode:" + pushDhMessage.getDeviceSn() + "; 未查到设备相关数据!");

        String deviceId = find.getDeviceId();

        System.out.println("find:" + find);

        //   DeviceErrorRecordPo deviceErrorRecordPo = new DeviceErrorRecordPo();

        find.setDeviceId(find.getDeviceSn());
        find.setDeviceName(find.getDeviceName());
        //   find.setAlarmHubName(find.getDeviceName());

        String newErrorType = null;

        if("SIAEvent".equals(pushDhMessage.getMsgType())){
            //同步分区的布防状态
            List<RoomPo> roomPos = roomMapper.selectRoomByDeviceSn(find.getDeviceSn());
            if(CollectionUtils.isNotEmpty(roomPos)){
                for (RoomPo roomPo : roomPos){
                    GetAreaInfosReq getAreaInfosReq = new GetAreaInfosReq();
                    getAreaInfosReq.setDeviceId(find.getDeviceSn());
                    getAreaInfosReq.setAreaId(roomPo.getRoomCode());
                    Result<GetAreaArmModeRes> areaArmMode = dhDeviceService.getAreaArmMode(getAreaInfosReq);
                    List<ArmModesRes> armModes = JSONArray.parseArray(JSONObject.parseObject(String.valueOf(areaArmMode.getData())).get("armModes").toString(), ArmModesRes.class);
                    if(CollectionUtils.isNotEmpty(armModes)){
                        String mode = armModes.get(0).getMode();
                        if(!mode.equals(roomPo.getMode())){
                            roomPo.setMode(mode);
                            roomMapper.updateById(roomPo);
                        }
                    }
                }
            }
        }

        if ("online".equals(pushDhMessage.getMsgType()))
            pushDhMessage.setMsgType("Device online");
        else if ("offline".equals(pushDhMessage.getMsgType()))
            pushDhMessage.setMsgType("Device offline");
        else {
            newErrorType = deviceErrorRecordMapper.findNewErrorType(find.getDeviceType(), find.getAccessoryType(), pushDhMessage.getMsgType());
        }


        //    String newErrorType = deviceErrorRecordMapper.findNewErrorType(find.getDeviceType(), find.getAccessoryType(), pushDhMessage.getMsgType());

        find.setErrorType(StringUtil.isNotEmpty(newErrorType) ? newErrorType : pushDhMessage.getMsgType());
        find.setStatus("未处理");

        // 查询设备所在时区
        TimeZoneDictRes deviceTimeZone = deviceService.findDeviceTimeZone(find.getDeviceSn());
        // 查询对照表
        String timeZoneDict = deviceErrorRecordMapper.findTimeZoneDict(deviceTimeZone == null ? "" : deviceTimeZone.getAreaDesc());

        TimeZone sourceTimeZone = TimeZone.getTimeZone(ZoneId.systemDefault());
        TimeZone targetTimeZone = timeZoneDict == null ? TimeZone.getTimeZone(ZoneId.systemDefault()) : TimeZone.getTimeZone(timeZoneDict);

        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(pushDhMessage.getAlarmTime());

        long sourceTimeInMillis = calendar.getTimeInMillis() - sourceTimeZone.getRawOffset() + targetTimeZone.getRawOffset();

        calendar.setTimeInMillis(sourceTimeInMillis);

        System.out.println("设备所在时区:" + deviceTimeZone.getAreaDesc() + "; 对照时区:" + timeZoneDict);

        find.setErrorTime(calendar.getTime());
        find.setIsRead(0);
        find.setType(pushDhMessage.getType());

        // 图片
        find.setPicUrls(pushDhMessage.getPicUrls());

        this.save(find);

        if (find.getType() == 1 || find.getType() == 2 || find.getType() == 3 || find.getType() == 4) {
            // 新增消息到web站内信表
            DeviceErrorRecordMessagePo deviceErrorRecordMessagePo = new DeviceErrorRecordMessagePo();
            deviceErrorRecordMessagePo.setDerId(find.getId());
            deviceErrorRecordMessagePo.setErrorType(find.getErrorType());
            deviceErrorRecordMessagePo.setSiteId(find.getSiteId());
            deviceErrorRecordMessagePo.setSiteName(find.getSiteName());
            deviceErrorRecordMessagePo.setErrorTime(find.getErrorTime());
            deviceErrorRecordMessagePo.setIsRead(0);
            deviceErrorRecordMessagePo.setType(find.getType());

            deviceErrorRecordMessageService.save(deviceErrorRecordMessagePo);
        }

        // 查询该设备或配件租赁的用户id, 并新增到read表
        List<String> consumerIdByDeviceId = deviceErrorRecordMapper.findConsumerIdByDeviceId(deviceId, find.getRoomId());

        List<DeviceErrorRecordReadPo> reads = new ArrayList<>();

        for (String s : consumerIdByDeviceId) {
            DeviceErrorRecordReadPo deviceErrorRecordReadPo = new DeviceErrorRecordReadPo();
            deviceErrorRecordReadPo.setConsumerId(s);
            deviceErrorRecordReadPo.setDerId(find.getId());
            deviceErrorRecordReadPo.setIsRead(0);
            reads.add(deviceErrorRecordReadPo);
        }

        deviceErrorRecordReadService.saveBatch(reads);

        if (consumerIdByDeviceId == null || consumerIdByDeviceId.isEmpty()) {
            deviceErrorRecordMapper.addAppPushMessage("deviceId:" + deviceId + ";没有租赁的用户,无需推送");
            return;
        }

        // 推动消息到userApp
        // 1. 先查询cid(根据设备id查询到consumerId在查到fcm_token) - consumer表fcm_token字段
        List<String> cids = deviceErrorRecordMapper.findCidByConsumerIds(consumerIdByDeviceId);

        if (find.getType() != 99 && cids != null && !cids.isEmpty()) {

            String title = "";
            String content = "";

            switch (find.getType()) {
                case 1:
                    title = "Alarm";
                    break;
                case 2:
                    title = "Error";
                    break;
                case 3:
                    title = "Events";
                    break;
                case 4:
                    title = "Notification";
                    break;
                default:
                    break;
            }

            String accessoryType = find.getAccessoryType();
            if (accessoryType != null && StringUtil.isNotEmpty(accessoryType)) {  // 配件
                switch (accessoryType) {
                    case "1":
                        content = "Smoke detector";
                        break;
                    case "2":
                        content = "Wireless keyfob";
                        break;
                    case "3":
                        content = "External Siren";
                        break;
                    case "4":
                        content = "Door Detector";
                        break;
                    case "5":
                        content = "Door Detector Plus";
                        break;
                    case "6":
                        content = "Pir Detertor";
                        break;
                    default:
                        break;
                }
                content += "-" + find.getRoomName() + "-" + find.getSiteName();
            } else { // 设备
                switch (find.getDeviceType()) {
                    case "1":
                        content = "IPC";
                        break;
                    case "2":
                        content = "Alarm Hub";
                        break;
                    case "3":
                        content = "Other";
                        break;
                    case "99":
                        content = "Accessory";
                        break;
                    default:
                        break;

                }
                content += "-" + find.getSiteName();
            }

            deviceErrorRecordMapper.addAppPushMessage("app推送: cid:" + cids + "; title:" + title + "; content:" + content);
            // 2. 调用推送接口
            pushUtil.pushListByCid(cids, title, content, true);
            // 3.调用短信通知和语音通知
            alarmNoticeSettingService.sendSmsAndSendVoice(find.getDeviceSn(), content);

        }
    }

    /**
     * 添加报警配置
     *
     * @param derConfigAddReq
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addDerConfig(DerConfigAddReq derConfigAddReq) {
        AddArcConfigReq addArcConfigReq = new AddArcConfigReq();

        //设备sn码
        addArcConfigReq.setDeviceId(derConfigAddReq.getDeviceSn());

        //协议类型
        addArcConfigReq.setProtocolType(derConfigAddReq.getProtocolType());

        //主选地址ip
        addArcConfigReq.setPrimaryAddressIp(derConfigAddReq.getPrimaryAddressIp());

        //主选地址端口
        addArcConfigReq.setPrimaryAddressPort(derConfigAddReq.getPrimaryAddressPort());

        if (StringUtil.isNotEmpty(derConfigAddReq.getAlternativeAddressIp()) && derConfigAddReq.getAlternativeAddressPort() != null) {
            //备选地址
            AlternativeAddresses alternativeAddresses = new AlternativeAddresses();
            alternativeAddresses.setIp(derConfigAddReq.getAlternativeAddressIp());
            alternativeAddresses.setPort(derConfigAddReq.getAlternativeAddressPort());
            addArcConfigReq.setAlternativeAddresses(new ArrayList<>() {{
                add(alternativeAddresses);
            }});
        }

        SIA_DC09 siaDc09 = new SIA_DC09();
        //中央账号
        siaDc09.setAccount(derConfigAddReq.getAccount());
        //重新上传周期
        siaDc09.setRetransmissionDeadline(derConfigAddReq.getReportEvents());
        addArcConfigReq.setSIA_DC09(siaDc09);


        dhDeviceService.addArcConfig(addArcConfigReq);

        DeviceErrorRecordConfigPo deviceErrorRecordConfigPo = new DeviceErrorRecordConfigPo();
        BeanUtil.copyProperties(derConfigAddReq, deviceErrorRecordConfigPo);

        deviceErrorRecordConfigMapper.delDerConfigFindRes(deviceErrorRecordConfigPo.getDeviceSn());
        deviceErrorRecordConfigMapper.insert(deviceErrorRecordConfigPo);
    }

    /**
     * 查询报警配置
     *
     * @param deviceSn
     * @return
     */
    @Override
    public DerConfigFindRes findDerConfig(String deviceSn) {
        return deviceErrorRecordConfigMapper.findDerConfigFindRes(deviceSn);
     /*   ComId comId = new ComId();
        comId.setDeviceId(deviceSn);

        Result<GetArcConfigRes> arcConfig = dhDeviceService.getArcConfig(comId);

        if (arcConfig == null || arcConfig.getData() == null)
            return null;

        GetArcConfigRes data = arcConfig.getData();

        DerConfigFindRes derConfigFindRes = new DerConfigFindRes();

        derConfigFindRes.setProtocolType(data.getProtocolType());
        derConfigFindRes.setPrimaryAddressIp(data.getPrimaryAddressIp());
        derConfigFindRes.setPrimaryAddressPort(data.getPrimaryAddressPort());

        List<AlternativeAddresses> alternativeAddresses = data.getAlternativeAddresses();
        if (alternativeAddresses != null && !alternativeAddresses.isEmpty()) {
            derConfigFindRes.setAlternativeAddressIp(alternativeAddresses.get(0).getIp());
            derConfigFindRes.setAlternativeAddressPort(alternativeAddresses.get(0).getPort());
        }

        SIA_DC09 siaDc09 = data.getSIA_DC09();
        if (siaDc09 != null) {
            derConfigFindRes.setAccount(siaDc09.getAccount());
//            derConfigFindRes.setReportEvents(siaDc09.getReportEvents());
        }


        return derConfigFindRes;*/
    }

    /**
     * web查询报警
     *
     * @return
     */
    public Page<DeviceErrorRecordListRes> findWebRecordList(WebDerReq req) {

        LoginUser loginUser = SecurityUtil.getLoginUser();

        String userId = loginUser != null ? loginUser.getUserId() : null;

        if (StringUtil.isEmpty(userId))
            throw new AppException("user.id.not.null");

        req.setUserId(userId);

        Page<DeviceErrorRecordListRes> webRecordList = deviceErrorRecordMapper.findWebRecordList(req, new Page<>(req.getPageNo(), req.getPageSize()));

        /*LambdaQueryWrapper<DeviceErrorRecordPo> wrapper = new LambdaQueryWrapper<>();

        if(ObjectUtil.isNotEmpty(req.getSiteId()))
            wrapper.eq(DeviceErrorRecordPo::getSiteId,req.getSiteId());

        if(ObjectUtil.isNotEmpty(req.getRoomId()))
            wrapper.eq(DeviceErrorRecordPo::getRoomId, req.getRoomId());

        List<String> errorTypes = req.getErrorType();
        if(ObjectUtil.isNotEmpty(errorTypes)){
            wrapper.and(i -> {
                for (int j = 0; j < errorTypes.size(); j++) {
                    String s1 = errorTypes.get(j);
                    i.or(e -> e.eq(DeviceErrorRecordPo::getErrorType,s1));
                }
            });
        }

        List<String> siteId = req.getSiteId();

        if(ObjectUtil.isNotEmpty(siteId)){
            wrapper.and(i -> {
                for (int j = 0; j < siteId.size(); j++) {
                    String s1 = siteId.get(j);
                    i.or(e -> e.eq(DeviceErrorRecordPo::getSiteId,s1));
                }
            });
        }

        if(ObjectUtil.isNotEmpty(req.getStartDate()))
            wrapper.ge(DeviceErrorRecordPo::getErrorTime, req.getStartDate());

        if(ObjectUtil.isNotEmpty(req.getEndDate()))
            wrapper.le(DeviceErrorRecordPo::getErrorTime, req.getEndDate());


        Page<DeviceErrorRecordPo> page = this.page(new Page<>(req.getPageNo(), req.getPageSize()), wrapper);
        Page<DeviceErrorRecordListRes> resPage = new Page();
        BeanUtil.copyProperties(page,resPage);*/
        return webRecordList;
    }

    @Override
    public void export(WebDerReq req, HttpServletResponse response) {
        LoginUser loginUser = SecurityUtil.getLoginUser();

        String userId = loginUser != null ? loginUser.getUserId() : null;

        if (StringUtil.isEmpty(userId))
            throw new AppException("user.id.not.null");

        req.setUserId(userId);

        if (req.getIds() != null && !req.getIds().isEmpty()) {
            WebDerReq newReq = new WebDerReq();
            newReq.setUserId(userId);
            newReq.setIds(req.getIds());
            newReq.setType(req.getType());
            req = newReq;
        }

        List<DeviceErrorRecordExportRes> webRecordListExport = deviceErrorRecordMapper.findWebRecordListExport(req);

        PoiUtil.writeExcelToResponse((req.getType() != null && req.getType() == 2) ? "故障消息" : "告警消息", DeviceErrorRecordExportRes.class, webRecordListExport, response);

    }

}
